//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "elrudcbits.h"

#if DBGPTK
extern int printk(const char *fmt, ...);
#else
#define printk(x, ...)
#endif

void msleep(unsigned int ms);
#define USB_OTG_ID_GPIO41   (1 << 9)  //GPDR1
#define USB_FULL_SPD_GPIO40 (1 << 8)  //GPDR1
#define USB_PLUGIN_GPIO107 (1 << 11) //GPDR3

#if 0
static void xxxtoa(
    unsigned long val,
    char *buf,
    unsigned radix,
    int is_neg
    )
{
    char *p;                /* pointer to traverse string */
    char *firstdig;         /* pointer to first digit */
    char temp;              /* temp char */
    unsigned digval;        /* value of digit */

    p = buf;

    if (is_neg) {
        /* negative, so output '-' and negate */
        *p++ = '-';
        val = (unsigned long)(-(long)val);
    }

    firstdig = p;           /* save pointer to first digit */

    do {
        digval = (unsigned) (val % radix);
        val /= radix;       /* get next digit */

        /* convert to ascii and store */
        if (digval > 9)
            *p++ = (char) (digval - 10 + 'a'); /* a letter */
        else
            *p++ = (char) (digval + '0');       /* a digit */
    } while (val > 0);

    /* We now have the digit of the number in the buffer, but in reverse
       order.  Thus we reverse them now. */

    *p-- = '\0';            /* terminate string; p points to last digit */

    do {
        temp = *p;
        *p = *firstdig;
        *firstdig = temp;   /* swap *p and *firstdig */
        --p;
        ++firstdig;         /* advance to next two digits */
    } while (firstdig < p); /* repeat until halfway */
}

/* Actual functions just call conversion helper with neg flag set correctly,
   and return pointer to buffer. */

char *  bsp_itoa(int val, char *buf, int radix)
{
    if (radix == 10 && val < 0)
        xxxtoa((unsigned long)val, buf, radix, 1);
    else
        xxxtoa((unsigned long)(unsigned int)val, buf, radix, 0);
    return buf;
}
#endif

/* soft_connect_hook()
 * Some devices have platform-specific circuitry to make USB
 * not seem to be plugged in, even when it is. This allows
 * software to control when a device 'appears' on the USB bus
 * (after Linux has booted and this driver has loaded, for
 * example). If you have such a circuit, control it here.
 */

extern void elr_connect_hook(int enable)
{
    if (enable) {
        /* high GPIO40 (B_USB_FULLSPEED), pull-up USBC_P line */
        GAFR1_L &= ~0x00030000;
        GPDR1 |= 0x00000100;
        GPCR1 = 0x00000100;     /* Clear and set */

        /* GPIO107(B_USB_DEC_N) AF0 */
        GAFR3_L &= ~0x00C00000;
        GPDR3   &= ~USB_PLUGIN_GPIO107;   /* set as input */

        /* GPIO41 (B_OTG_ID) AF0 */
        GAFR1_L &= ~0x000C0000;
        GPDR1 &= ~0x00000200;   /* set as input */

        /* GPIO39 (B_USB_CON_DET) AF0 */
        GAFR1_L &= ~(3 << 14);
        GPDR1 |= (1 << 7);   /* set as output low */
        GPCR1 |= (1 << 7);

        /* high GPIO40 (B_USB_FULLSPEED), pull-up USBC_P line */
        GAFR1_L &= ~0x00030000;
        GPDR1 |= 0x00000100;
        GPSR1 = 0x00000100;
    }
    else {

        /* high GPIO40 (B_USB_FULLSPEED), pull-up USBC_P line */
        GAFR1_L &= ~0x00030000;
        GPDR1 |= 0x00000100;
        GPCR1 = 0x00000100;     /* Clear and set */

        /* GPIO107(B_USB_DEC_N) AF0 */
        GAFR3_L &= ~0x00C00000;
        GPDR3   &= ~USB_PLUGIN_GPIO107;   /* set as input */

        /* GPIO41 (B_OTG_ID) AF0 */
        GAFR1_L &= ~0x000C0000;
        GPDR1 &= ~0x00000200;   /* set as input */

        /* GPIO39 (B_USB_CON_DET) AF0 */
        GAFR1_L &= ~(3 << 14);
        GPDR1 |= (1 << 7);   /* set as output low */
        GPCR1 |= (1 << 7);
    }

    msleep(10);     /* Delay 10 ms */
}

/* disable the UDC at the source */
void elr_udc_disable(void)
{

//    ICMR &= ~(INTC_USBCLIENT);
    /* clear UDC-enable */
    //udc_clear_mask_UDCCR( UDCCR_UDE);
    UDCCR &= ~(UDCCR_UDE);
    UDCICR0 = 0x00000000;
    UDCICR1 = 0x00000000;
    UDCISR0 = 0xFFFFFFFF;
    UDCISR1 = 0xFFFFFFFF;
    UP2OCR =  0x00000000;
    /* Disable clock for USB device */
    CKEN &= ~CKEN11_USB;
}

/*  enable the udc at the source */
void elr_udc_enable(void)
{
//    char cbuf[12];
    /* Enable clock for USB device */
    CKEN |= CKEN11_USB;
//    ICMR |= INTC_USBCLIENT;
    /* UDC Endpoints */
    /* endpoint A ~ BULK, IN, MPS: 64bytes, Double-buffering, configuration 1, interface 0,
     * altsetting 0, endpoint 1
     */
    UDCCRA = ( UDCCRZ_EE | MAX_PKT_BULK_64 | EP_DIRECTION_IN | EP_TYPE_BULK |
               EP_NUM_1  | ALTERNATE_INTERFACE_SETTING_0 | INTERFACE_SETTING_0 |
               CONFIG_NUM_2 | UDCCRZ_DE ) ;
    /* endpoint B ~ BULK, OUT,MPS: 64bytes, Double-buffering, configuration 1, interface 0,
     * altsetting 0, endpoint 2
     */
    UDCCRB = ( UDCCRZ_EE | MAX_PKT_BULK_64 | EP_DIRECTION_OUT | EP_TYPE_BULK |
               EP_NUM_2  | ALTERNATE_INTERFACE_SETTING_0 | INTERFACE_SETTING_0 |
               CONFIG_NUM_2 | 0 ) ;//UDCCRZ_DE
    /* endpoint C Int Dummy endpoint */
    UDCCRC = ( UDCCRZ_EE | MAX_PKT_IN | EP_DIRECTION_IN | EP_TYPE_INTERRUPT |
               EP_NUM_3  | ALTERNATE_INTERFACE_SETTING_0 | INTERFACE_SETTING_0 |
               CONFIG_NUM_2 | UDCCRZ_DE ) ;
    UP2OCR = 0x20010;
    UDCWAKEUP |= 0x00008000;

    /* enable endpoint 0, A, B's Packet Complete Interrupt. */
    UDCICR0 = ( UDCICR0_IE0_0 | UDCICR0_IE0_1 );
    UDCICR1 = ( UDCICR1_IERS | UDCISR1_IRCC);
    /* clear the interrupt status/control registers */
    UDCISR0 = 0xffffffff;
    UDCISR1 = 0xffffffff;

    /* set UDC-enable */
    //udc_set_mask_UDCCR( UDCCR_UDE);
    UDCCR |= UDCCR_UDE;

    if (UDCCR & UDCCR_EMCE) {
        printk("Error: UDC Endpoint Memory configuration error\n");
    }
    else {
        printk("UDC Endpoint Memory configuration ok.\n");
    }
    while (1) {
        if (UDCCR & UDCCR_UDA) {
            /* There's a reset on the bus,
             * clear the interrupt bit and keep going
             */
            break;
            /* udc_ack_int_UDCCR( UDCCR_RSTIR); */
        }
        printk("waiting reset on bus\n");
    }
}
